#
# $Id$
#
# RTEMS Project (http://www.rtems.org/)
# Copyright 2007 Chris Johns (chrisj@rtems.org)
# All rights reserved.
#
# This file is part of The RTEMS Toolkit.
#
# The RTEMS Toolkit is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# The RTEMS Toolkit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with The RTEMS Toolkit; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# Execute commands as defined in the configuration file.
#

import config
import environ
import error
import execute

def run(exe, config, commands, substs = None, args = None,
        cwd = None, env = None, return_exitcode = False):
    """Run a command list read from the configuration files. This is a list
    that moves from left to right as a series of commands parts with options
    where each command part pipes to the next and the output of the final
    command part is piped to the output handler.

    The commands come from the configuration file as tuples of:
    
        (type, label, pos)

    where type is the type of label, a label and pos is the offset into
    the pre-processed configuration file buffer.

    The command list is:

        shell || spawn => [command [args]] | [command [args]]
    """
    if commands is None or len(commands) == 0:
        raise error.internal('command is invalid')
    if type(commands) is tuple and len(commands) == 2:
        commands = config.follow(commands[0], commands[1], execute.check_type)
    if not execute.check_type(commands[0][1]):
        config.ouch(commands[0][2], 'invalid command type [shell or spawn]')
    if commands[1][0] != 'req':
        config.ouch(commands[1][2], 'invalid command format: ' + commands[1][0])
    shell = False
    if commands[0][1] == 'shell':
        shell = True
    # We support a single pipe which we can redirect a file into
    # or out of.
    stdin = None
    if commands[:-1][0] == 'pipe':
        config.ouch(commands[:-1][2], 'cannot end a command with a pipe')
    input = None
    if len(commands) >= 4 and commands[3][0] == 'redirin':
        fname = execute.arg_subst(commands[2][1], args)
        input = open(fname)
    procs = []
    cpart = ''
    for c in commands[2:]:
        if c[0] == 'pipe':
            if args:
                cpart = execute.arg_list(cpart)
                cpart.extend(args)
            ec, proc = exe.command_subst(cpart, substs, capture = False,
                                         cwd = cwd, env = env,
                                         stdin = stdin, stdout = execute.PIPE)
            if ec != 0:
                if return_exitcode:
                    for proc in procs:
                        del proc
                    return ec, cpart
                cmd = execute.arg_subst_str(cpart, args)
                raise error.general('command error: ' + str(ec) + ': ' + cmd)
            cpart = ''
            stdin = proc.stdout
            procs.append(proc)
        else:
            cpart += ' ' + c[1]
    if len(cpart) == 0:
        raise error.general('no command found')
    if args:
        cpart = execute.arg_list(cpart)
        cpart.extend(args)
    ec, proc = exe.command_subst(cpart, substs, cwd = cwd, env = env, stdin = stdin)
    if ec != 0 and not return_exitcode:
        cmd = execute.arg_subst_str(cpart, args)
        raise error.general('command error: ' + str(ec) + ': ' + cmd)
    exe.capture(proc)    
    del proc
    for proc in procs:
        del proc
    return ec, cpart

if __name__ == "__main__":
    try:
        c = config.data()
        c.load('test/commands.cf')
        print c.format(True)
        e = environ.system(c, verbose = True)
        exe = execute.execute(error_prefix = 'ERR', verbose = True)
        run(exe, c, (e.get('system'), 'test1'))
        del exe
    except error.error, e:
        print e
